#include <fwk/RunController.h>
#include <fwk/CentralConfig.h>
#include <fwk/VModule.h>
//#include <utl/ErrorLogger.h>
//using namespace fwk;

#include <det/Detector.h>
#include <sdet/SDetector.h>
#include <sdet/Station.h>
//using sdet::SDetector;

#include <evt/Header.h>
#include <evt/Event.h>

#include <sevt/SEvent.h>
#include <sevt/Header.h>
#include <sevt/EventTrigger.h>
#include <sevt/Station.h>
#include <sevt/StationTriggerData.h>
#include <sevt/StationRecData.h>
#include <sevt/PMT.h>
#include <sevt/PMTRecData.h>
#include <sevt/PMTCalibData.h>
//using sevt::SEvent;

#include <fevt/FEvent.h>
#include <fevt/Eye.h>
#include <fevt/EyeHeader.h>

//#include <utl/ErrorLogger.h>
#include <utl/Trace.h>
#include <utl/Reader.h>
#include <utl/TimeStamp.h>
#include <utl/Point.h>
#include <utl/TimeStamp.h>
//using namespace utl;

#include <fstream>
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <ctime>
using namespace std;

#include "see.h"
#include "iOfflineFile.h"

see::see():
  evento(0),
  eventFile(0)
{
  //cout << "\nHola Javo.\n\n";
  clock_t start = clock();
  cout << "\x1b[32mInicializando el detector (puede tomar un par de minutos)..  \x1b[0m\n\n";

  
  string boot="bootstrap.xml";
  fwk::CentralConfig::GetInstance(boot);
  det::Detector& det=det::Detector::GetInstance();
  utl::CoordinateSystemPtr siteCS=det.GetSiteCoordinateSystem();
  
  det.Update(utl::TimeStamp(2004, 12, 22, 13, 45, 32, 1000));
  //std::list<int> lista = det.GetSDetector().GetFullStationList();
  //for(list<int>::const_iterator it=lista.begin();it!=lista.end();it++) cout << *it <<" ";
  
  for(sdet::SDetector::StationIterator dsIt=det.GetSDetector().StationsBegin();dsIt!=det.GetSDetector().StationsEnd();++dsIt){
    tStation station;
    station.lt=eNone;
    station.sId=dsIt->GetId();
    station.x=dsIt->GetPosition().GetX(siteCS);
    station.y=dsIt->GetPosition().GetY(siteCS);
    statList.push_back(station);
  }
  
  cout<< "\x1b[32mListo!\n";
  clock_t ends = clock();
  cout <<"\x1b[31mHa tomado "<<(double) (ends - start) / CLOCKS_PER_SEC <<" segundos\x1b[0m\n";
  
  //if(openFile(filename)==0) throw "ioError";
}

bool see::openFile(char* filename) //return 0 if there is an error
{
  clock_t start = clock();
  cout << "\x1b[32mAbriendo el archivo \""<<filename<<"\" (puede tomar un ratito)..\x1b[0m\n\n";
  if(eventFile){
    eventFile->Close();
    delete eventFile;
    eventFile = 0;
  }
  
  try{
    eventFile = new iOF::iOfflineFile(filename);
    cout<<"dentro del try\n";
  }
  catch(char const *message){
    return 0;
  }
  cout<<"despues del catch\n";
  if(eventFile->GetNEvents()<1) return 0;
  cout<<"despues de GetNEvents\n";
  eventsList.clear();
  for(int i=0;i<eventFile->GetNEvents();i++){
    cout << "\x1b[35mleyendo "<<i+1 <<" de " <<eventFile->GetNEvents()<<endl;
    
    if(evento){
      delete evento;
      evento=0;
    }
    evento=new evt::Event();
    tEventsummary eventSummary;
    eventFile->SetCurEventNo(i);
    eventFile->ReadOnlySHeaderAndSTrigger(*evento);
    int contador=0;
    sevt::SEvent& sEvent=evento->GetSEvent();
    if(!sEvent.HasTrigger()) continue;
    cout << "Id de T3: "<<sEvent.GetTrigger().GetAlgorithm()<< endl;
    if(sEvent.GetTrigger().GetAlgorithm()=="None") continue;
    for (sevt::SEvent::StationIterator sIt = sEvent.StationsBegin();sIt != sEvent.StationsEnd(); ++sIt){
      if(sIt->IsCandidate()) contador++;
    }
    eventSummary.Id=sEvent.GetHeader().GetId();
    eventSummary.fileIndex=i;
    eventSummary.candN=contador;
    eventsList.push_back(eventSummary);
  }
  delete evento;
  evento=0;
  clock_t ends = clock();
  cout <<"\x1b[32mListo!\n";
  cout <<"\x1b[31mHa tomado "<<(double) (ends - start) / CLOCKS_PER_SEC <<" segundos\x1b[0m\n";
  
  if(eventsList.size()<1) return 0;
  
  for(int i=0;i<eventFile->GetNEvents();i++) cout<<eventsList[i].Id<<" "<<eventsList[i].candN<<endl;
  return 1;
}

bool see::readEvent(int eventIndexNo)
{
  clock_t start = clock();
  cout <<"\x1b[32mLeyendo evento: \x1b[0m"<<eventIndexNo<<endl;
  det::Detector& det=det::Detector::GetInstance();
  if(evento){
    delete evento;
    evento=0;
  }
  evento=new evt::Event();
  eventFile->SetCurEventNo(eventIndexNo);
  eventFile->ReadEvent(*evento);
  sevt::SEvent& sEvent=evento->GetSEvent();
  vector<utl::TimeStamp> times;

  candList.clear();
  
  for(int i=0;i<statList.size();i++){
    statList[i].lt=eNone;
    sevt::Station& eventStation=sEvent.GetStation(statList[i].sId);
    if(eventStation.IsCandidate()) {
      tCandidate candTank;
      candTank.sId=statList[i].sId;
      times.push_back(eventStation.GetTraceStartTime());
      if(eventStation.GetTriggerData().IsTimeOverThreshold()) candTank.lt=eToT;
      else if(eventStation.GetTriggerData().IsThreshold() && (eventStation.GetTriggerData().GetWindowSize()==0)) candTank.lt=eThr2;
      else if(eventStation.GetTriggerData().IsThreshold() && !(eventStation.GetTriggerData().GetWindowSize()==0)) candTank.lt=eThr1;
      else candTank.lt=eNone;
      candTank.ns=-1;
      candTank.totalVem=eventStation.GetRecData().GetTotalSignal();
      candTank.riseTime=eventStation.GetRecData().GetRiseTime();
      candTank.fallTime=eventStation.GetRecData().GetFallTime();
      
      candList.push_back(candTank);
      statList[i].lt=candTank.lt;
    }
  }
  
  utl::TimeStamp minTime=times[0];
  for(int i=1;i<times.size();i++){
    if(minTime>times[i]) minTime=times[i];
  }
  for(int i=0;i<candList.size();i++){
    candList[i].ns=(times[i] - minTime).GetInterval();
  }
  
  clock_t ends = clock();
  cout <<"\x1b[32mListo!\n";
  cout <<"\x1b[31mHa tomado "<<(double) (ends - start) / CLOCKS_PER_SEC <<" segundos\x1b[0m\n";
  cout << "\nFinal feliz!\n";
  return 1;
}


pmtTrace* see::getPmtTraces(int sId)
{
  sevt::SEvent& sEvent=evento->GetSEvent();
  int size = 0;
  unsigned int startBin = sEvent.GetStation(sId).GetRecData().GetSignalStartSlot();
  if(startBin>=2) startBin-=2;
  unsigned int stopBin = sEvent.GetStation(sId).GetRecData().GetSignalEndSlot();
  size = stopBin-startBin;
  
  for(int i=0;i<3;i++){
    sevt::PMTRecData &pmtRec = sEvent.GetStation(sId).GetPMT(i+1).GetRecData();
    sevt::PMTCalibData &pmtCal = sEvent.GetStation(sId).GetPMT(i+1).GetCalibData();
      
    double kCal=pmtCal.GetVEMPeak()/pmtCal.GetVEMCharge();
    const utl::TraceD& totalVEMtrace = kCal*pmtRec.GetVEMTrace();
    //cout<<"\n\nantes de setTrace\n\n";
    trace.setTrace(i+1,size,&totalVEMtrace[startBin]);
    //cout<<"\n\ndespues de setTrace\n\n";
  }
  
  return &trace;
}

see::~see()
{
  if(evento) delete evento;
  if(eventFile){
    eventFile->Close();
    delete eventFile;
  }
}

pmtTrace::pmtTrace()
{
  for(int i=0;i<3;i++) dataFlag[i]=0;
  xFlag=0;
}

pmtTrace::~pmtTrace()
{
  //cout << "\nDestructor de pmtTrace\n";
  if(xFlag) delete[] x;
  //cout << "\ndespues de borrar x\n";
  for(int i=0;i<3;i++) if(dataFlag[i]) delete[] y[i];
  //cout << "\ndespues de borrar y[i]\n";
}

genTrace pmtTrace::getTrace(int pmtId)
{
  return totalTrace[pmtId-1];
}

void pmtTrace::setTrace(int pmtId,int size,const double* yTrace)
{
  if(xFlag==0){
    x=new double[size];
    for(int i=0;i<size;i++) x[i] = i*25;
    xFlag=1;
  }
  totalTrace[pmtId-1].x=x;
  //cout << "\ndespues de las x..\nDireccion: "<<totalTrace[pmtId-1].x<<endl;
  totalTrace[pmtId-1].size=size;
  y[pmtId-1]=new double[size];
  //cout << "despues de crear las y..\n";
  for(int i=0;i<size;i++) y[pmtId-1][i] = yTrace[i];
  //cout << "despues de llenar las y..\n";
  totalTrace[pmtId-1].y=y[pmtId-1];
  dataFlag[pmtId-1]=1;
  //cout << "despues de todo dentro de setTrace..\n";
}
